#include "StringPtrMap.h"
#include "hash_prime.h"
namespace qb{
	namespace base{

		StringPtrMap::StringPtrMap(int capcity)
		{
			capcity = qb::base::GetHashPrimeLargerThan(capcity);
			m_string_buf = new SStringBuf();
			m_hashmap.Build(capcity);
			m_cache.SetUsePool(false);
		}

		StringPtrMap::~StringPtrMap()
		{
			//BS_METRICS("");
			Collector collector(&m_cache);
			collector.Enum(m_hashmap);
			m_hashmap.Clear();
			if (m_string_buf)
				delete m_string_buf;
		}

		qb::base::StringPtrMap::StringId StringPtrMap::SetAt(const char* name, void* ptr)
		{
			Key key(name, ptr);
			unsigned int hash = key.GetHash();
			Entry* et = m_hashmap.Find(key, hash);
			if (et == 0)
			{
				key.id = m_string_buf->AddString(name, strlen(name));
				et = NewEntry(key);
				m_hashmap.Insert(et, hash);
				return key.id;
			}
			else
			{
				et->key.ptr = ptr;
				return et->key.id;
			}
		}

		bool StringPtrMap::Lookup(const char* name, void*& ptr)
		{
			Key key(name, 0);
			unsigned int hash = key.GetHash();
			Entry* et = m_hashmap.Find(key, hash);
			if (et)
				ptr = (void*)et->key.ptr;
			return et != 0;
		}

		void StringPtrMap::RemoveAll()
		{
			//BS_METRICS("");
			m_string_buf->Reset();
			Collector collector(&m_cache);
			collector.Enum(m_hashmap);
			m_hashmap.Clear();
		}

		void StringPtrMap::ExpandByRatio(double ratio)
		{
			int count = m_hashmap.GetCount();
			ratio = ratio < 0.4 ? 0.4 : ratio;
			ratio = ratio > 20 ? 20 : ratio;
			int length = (count < 10949 ? 10949 : count) / ratio;
			m_hashmap.Expand(length);
		}

		void StringPtrMap::InitHashTable(int capcity)
		{
			//BS_METRICS("InitHashTable:count:%d length:%d cap:%d",m_hashmap.GetCount(),m_hashmap.GetLength(),capcity);
			m_hashmap.Expand(capcity);
		}

		int StringPtrMap::GetBytes()const
		{
			int bytes = sizeof(*this);
			bytes += m_string_buf->GetBytes();
			bytes += m_hashmap.GetLength()*sizeof(Entry*);
			bytes += m_hashmap.GetCount()*sizeof(Entry);
			bytes += m_cache.GetCount()*(sizeof(Entry*) * 3 + sizeof(Entry));
			return bytes;
		}

		qb::base::StringPtrMap::Entry* StringPtrMap::NewEntry(const Key& k)
		{
			Entry* et = m_cache.Alloc();
			et->hashprev = et->hashnext = 0;
			et->key = k;
			return et;
		}

	}//namespace base;
}//namespace ss;
